#include <fstream>
#include <string>

#include "stage.h"

using namespace std;

EnemyWave::EnemyWave() {
  for(int i = 0; i < MAX_ENEMY_TYPE; ++i )
    _type[i]= _amount[i] = 0;
  _xTrigger = _killTrigger = 0;
  _killed = 0;
  _next = 0x00;
}

Stage::Stage(const char * filename) {
  __readFile(filename);
  _scrollStatus = 0;
  _player = 0x00;
  _currentMap = 0;
  _enemyOnMap = 0;
  _itemCreated = 0;
  _bossCreated = 0;
  
}

Stage::~Stage() {
  // Time to free some memory
  int i;
  destroy_bitmap(__getSprite());
  if ( _title ) destroy_bitmap(_title);
  for(i = 0; i < 5; ++i)
    if ( _enemyPack[i] ) _enemyPack[i]->__free();
  
}

int Stage::__update() {
  if ( _itemCreated == 0 ) {
    int i;
    for(i = 0; i < 10; ++i) {
      if ( !_itemArr[i] ) continue;
      if ( _itemArr[i]->__getX() < GAME_W + _currentMap * 500) {
        _itemArr[i]->__moveX(-500 * _currentMap);
        _itemVec->push_back(_itemArr[i]);
        _itemArr[i] = 0x00;
      }
    }    
    _itemCreated = 1; 
  }
  if (  _enemyOnMap <= 0 && _enemyArr[_currentMap] == 0x00
  && _player->__getX() + _player->__getSprite()->w/2 > 540 && _currentMap < 3) {
    __triggerScroll(10, 500);
  }
  if ( _scrollStatus ) __scroll();
  else {
    if ( _enemyArr[_currentMap] ) {
      if ( (_enemyArr[_currentMap]->_xTrigger == -1
      && _enemyArr[_currentMap]->_killTrigger == -1)
      || ( _enemyArr[_currentMap]->_xTrigger < _player->__getX() &&
      _enemyArr[_currentMap]->_xTrigger != 0 ))
        __createEnemies();
    }
    if ( _currentMap == 3 && _bossCreated == 0 ) { // Boss Creation
      _bossCreated = 1;
      Enemy * p = new Enemy(_player, _boss, TYPE_BOSS);
      p->__setY(GROUND_HEIGHT);
      p->__setX(640);
      _enemyVec->push_back(p);
      // Hud creation
      p->_HUDLife = new HUD(128,16);
      p->_HUDLife->_background = load_bitmap("images/hud/bossLife/life_background.bmp", NULL);
      p->_HUDLife->__setX(GAME_W/2 - (p->_HUDLife->__getSprite())->w/2);
      p->_HUDLife->__setY(GAME_H - 32);
      p->_HUDLife->_elementArr[0] = new Sprite("images/hud/bossLife/life.bmp");
      p->_HUDLife->_elementArr[0]->__setX(3);
      p->_HUDLife->_elementArr[0]->__setY(2);
      p->_HUDLife->__setStretchX(0, 122);
      p->_HUDLife->__update();
      _HUDVec->push_back(p->_HUDLife);
      
    }
  }
  return 0;
}

void Stage::__triggerScroll(int speed, int width) {
  _scrollSpeed = speed;
  _scrollStatus = 1;
  _scrollWidth = width;
}

int Stage::__isScrolling() { return _scrollStatus; }

void Stage::__scroll() {
  __moveX(-_scrollSpeed);
  if ( _player )
    if ( _player->__getX() + _player->__getSprite()->w/2 > 0 ) _player->__moveX(-_scrollSpeed);
  _scrollWidth -= _scrollSpeed;
  if ( _scrollWidth <= 0 ) { // Scroll ended
    _scrollStatus = 0;
    __moveX(-_scrollWidth);
    ++_currentMap;
    _itemCreated = 0;
  }
}


void Stage::__createEnemies() {
  if ( _enemyArr[_currentMap] ) {
    for(int i = 0;  i < MAX_ENEMY_TYPE; ++i) {
      for(int j = 0; j < _enemyArr[_currentMap]->_amount[i]; ++j) {
        Enemy * p = new Enemy(_player, _enemyPack[_enemyArr[_currentMap]->_type[i]], TYPE_RANGED);
        p->__setY(GROUND_HEIGHT);
        p->__setX(640 + j * 40 + i*60);
        _enemyVec->push_back(p);
        ++_enemyOnMap;
      }
    }
    EnemyWave * tmp = _enemyArr[_currentMap];
    _enemyArr[_currentMap] = _enemyArr[_currentMap]->_next;
    delete(tmp); // Cleaning
  }
}

void Stage::__killEnemy(int count) {
  _enemyOnMap -= count;
  if ( _enemyArr[_currentMap] )
    if ( ++_enemyArr[_currentMap]->_killed == _enemyArr[_currentMap]->_killTrigger )
      __createEnemies();
}
void Stage::__linkCharacter(Character * player) { _player = player; }
void Stage::__linkItemVec(vector<Item *>*itemVec) { _itemVec = itemVec; }

void Stage::__readFile(const char * filename) {
  ifstream dataFile;
  string sbuffer;
  int ibuffer;
  int wave = -1;
  int i, j, a;
  char path[64];
  EnemyWave * p;

  for(i = 0; i < 5; ++i ) _enemyArr[i] = 0x00;
  for(i = 0; i < 10; ++i) _itemArr[i] = 0x00;
  for(i = 0; i < 5; ++i) _enemyPack[i] = 0x00;
  _title = 0x00;
  _boss = 0x00;
  
  
  // Opening the file
  dataFile.open(filename);

  if ( !dataFile.is_open()) {
    allegro_message("Error could not open %s",filename);
    exit(-1);
  }
  /*
  * Stage Bitmap
  */
  dataFile >> sbuffer; // Path
  BITMAP * res = load_bitmap(sbuffer.c_str(), NULL);
  if ( !res ) {
    allegro_message("Error stage image: %s cannot be buffered", sbuffer);
    exit(-1);
  }
  __setBitmap(res);
  /*
  * Stage Title
  */
  dataFile >> sbuffer; // Title path
  res = load_bitmap(sbuffer.c_str(), NULL);
  if ( !res ) {
    allegro_message("Error stage title image: %s cannot be buffered", sbuffer);
    exit(-1);
  }
  _title = res;

  /*
  * Buffering Enemies
  */
  i = 0;
  while(!dataFile.eof()) {
    dataFile >> sbuffer;
    if ( sbuffer != "LOAD_ENEMY()" ) break;
    dataFile >> sbuffer;
    while( sbuffer != "END_ENEMY()" ) {
      _enemyPack[i] = new AnimatedSprite();
      strcpy(path, "data/");
      strcat(path, sbuffer.c_str());
      _enemyPack[i]->__readFile(path);
      ++i;
      dataFile >> sbuffer; 
    }
  }
  while(!dataFile.eof()) {
    if ( sbuffer == "START_WAVE()" ) ++wave;
    else break;
    p =_enemyArr[wave] = new EnemyWave();
    dataFile >> a;
    for(j = 0; j < a; ++j) {
      dataFile >> ibuffer;
      for(i = 0; i < ibuffer; ++i) {
        dataFile >> p->_type[i];
        dataFile >> p->_amount[i];
      }
      dataFile >> p->_xTrigger;
      dataFile >> p->_killTrigger;
      if ( j+1 < a ) {
        p->_next = new EnemyWave();
        p=p->_next;
      }
    }
    dataFile >> sbuffer;
    if ( sbuffer == "END_WAVE()" ) dataFile >> sbuffer;
    else break;
  }
  /*
  * Items buffering
  */
  while(!dataFile.eof()) {
    if ( sbuffer != "START_ITEM()" ) break;
    dataFile >> ibuffer;
    j = ibuffer;
    if ( j < 1 || j > 10 ) break;
    int id, cvalue[3], x;    
    for(i = 0; i < j; ++i) {
      dataFile >> ibuffer;
      x = ibuffer;
      dataFile >> ibuffer;
      id = ibuffer;
      dataFile >> ibuffer;
      cvalue[0] = ibuffer;
      dataFile >> ibuffer;
      cvalue[1] = ibuffer;
      dataFile >> ibuffer;
      cvalue[2] = ibuffer;            
      // Item creation      
      _itemArr[i] = new Item(id, cvalue[0], cvalue[1], cvalue[2]); 
      _itemArr[i]->__setX(x);
      _itemArr[i]->__setY(GROUND_HEIGHT);
    }
    dataFile >> sbuffer;
    dataFile >> sbuffer;    
  }
  /*
  * Boss buffering
  */
  while(!dataFile.eof()) {
    if (sbuffer != "LOAD_BOSS()" ) break;
    else dataFile >> sbuffer;
    _boss = new AnimatedSprite();
    strcpy(path, "data/");
    strcat(path, sbuffer.c_str());
    _boss->__readFile(path); 
  }    
}

BITMAP * Stage::__getTitle() { return _title; }

void Stage::__linkHUDVec(vector<HUD*>*HUDVec) { _HUDVec = HUDVec; }
